home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / pcr / pcr4_4.lha / UTILITIES / makescript.c < prev   
C/C++ Source or Header  |  1989-01-16  |  19KB  |  918 lines

  1. #ifndef lint
  2. static char rcsid[] = "@(#)$Header: /usr/src/local/bin/RCS/makescript.c,v 1.9 86/03/05 03:09:45 bin Exp $";
  3. #endif
  4.  
  5. /*
  6.  * Makescript - make a shell script which extracts files from itself
  7.  *
  8.  * Usage:
  9.  *    makescript [-k] [-p] [-t] [-v version] [-a file || -o file] file1 file2 ... filen
  10.  *
  11.  * Authors: Chris Torek, Liz Allen @ University of Maryland
  12.  *
  13.  * Last Edit: Alan Ishigo @ Xerox  on Oct 12, 1988
  14.  *
  15.  * Compilation command:
  16.  %  cc -O -s -o makescript makescript.c
  17.  */
  18.  
  19.  
  20. /*    Alan Ishigo -- Made the following changes to Makescript:
  21.  *
  22.  *    o    Added the option to preserve a and m times of files [-k]
  23.  *
  24.  *    o    Combined code from error.c into one file to ease further modifications
  25.  *
  26.  *    o    Added version switch [-v <version>] which will allow a version stamp 
  27.  *        to be put into the shar
  28.  *
  29.  *    o    Added checksum capabilities to enable stronger checking of files
  30.  *
  31.  *    o    Added procs "AddTimeKeeper" and "AddChksum" which contain the source
  32.  *        for the utime setter and the checksum generator respectively
  33.  *
  34.  *    Compilation command:  %cc -O -o makescript makescript.c
  35.  *
  36.  */
  37.  
  38. #define    max(a,b)    ((a) > (b) ? (a) : (b))
  39.  
  40. #include <stdio.h>
  41. #include <a.out.h>
  42. #include <pwd.h>
  43. #include <sys/types.h>
  44. #include <sys/dir.h>
  45. #include <sys/stat.h>
  46.  
  47. #define LIBNDIR /* non-libndir is probably no longer functional anyway */
  48.  
  49. int    RootID, BinID, DaemonID;
  50. FILE    *outfile;        /* Script being built */
  51. int    Level;            /* Nest level */
  52. char    WDir[BUFSIZ];        /* Working directory */
  53. char    serrbuf[BUFSIZ];    /* buffer for stderr */
  54. int    AssumeNoDataFiles;    /* true => assume all non-executable files
  55.                    are text */
  56. int    Errors;            /* total number of errors detected */
  57.  
  58. int    keeptimes;        /* flag whether or not to preserve a and m times */
  59.  
  60. extern int   errno;        /* system call error number */
  61.  
  62. extern int   optind;        /* argv[] index from getopt */
  63. extern char *optarg;        /* argument pointer from getopt */
  64.  
  65. char *_argv0;            /* argv[0], set by C startup code */
  66.  
  67.  
  68. char    *tail(), *protect();
  69. FILE    *popen();
  70.  
  71. main(argc, argv)
  72.     register int argc;
  73.     register char **argv;
  74. {
  75.     register int c;
  76.     int Append = 0, existed, rflag = 1;
  77.     char *outfname = 0;
  78.     char *version = 0;
  79.  
  80.     keeptimes = 0;
  81.     
  82.     setbuf(stderr, serrbuf);
  83.  
  84.     while ((c = getopt(argc, argv, "a:o:v:kpt")) != EOF) {
  85.         switch (c) {
  86.  
  87.         case 'a':
  88.             Append++;    /* ...and fall thru to 'o' */
  89.  
  90.         case 'o':
  91.             if (outfname)
  92.                 goto usage;
  93.             outfname = optarg;
  94.             break;
  95.         case 'v':
  96.             if (version) goto usage;
  97.             version = optarg;
  98.             break;
  99.         
  100.         case 'k':
  101.             keeptimes = 1;
  102.             break;
  103.  
  104.         case 'p':
  105.             rflag = 0;
  106.             break;
  107.  
  108.         case 't':
  109.             AssumeNoDataFiles++;
  110.             break;
  111.  
  112.         case '?':
  113.             goto usage;
  114.         }
  115.     }
  116.     if (optind >= argc) {
  117. usage:
  118.         fprintf(stderr, "\
  119. Usage: %s [-k] [-p] [-t] [-v <version>] [-a|-o <scriptname>] file1 [ file2... ]\n",
  120.             *argv);
  121.         exit(1);
  122.     }
  123.     if (outfname == 0)
  124.         outfile = stdout;
  125.     else {
  126.         existed = !access(outfname, 0);
  127.         if (existed && !Append) {    /* file exists... */
  128.             if (isatty(fileno(stdin))) {
  129.                 char answer[20];
  130.  
  131.                 fprintf(stderr, "%s exists.  Overwrite? ",
  132.                     outfname);
  133.                 fflush(stderr);
  134.                 fgets(answer, sizeof answer, stdin);
  135.                 if (*answer != 'y' && *answer != 'Y') {
  136.                     fprintf(stderr, "Whatever you say.\n");
  137.                     exit(1);
  138.                 }
  139.             }
  140.         }
  141.         outfile = fopen(outfname, Append ? "a" : "w");
  142.         if (outfile == NULL)
  143.             error(1, errno, "can't open %s", outfile);
  144.     }
  145.     GetIDs();
  146.     if (rflag) {
  147.         register FILE *f = popen("/bin/pwd", "r");
  148.         fread(WDir, 1, sizeof WDir, f);
  149.         WDir[strlen(WDir) - 1] = 0;
  150.         pclose(f);
  151.     }
  152.     if (!existed || !Append)
  153.         fprintf(outfile, "\
  154. : Run this shell script with \"sh\" not \"csh\"\n\
  155. PATH=/bin:/usr/bin:/usr/ucb:/etc:$PATH\n\
  156. export PATH\n\
  157. all=FALSE\n\
  158. if [ x$1 = x-a ]; then\n\
  159. \tall=TRUE\n\
  160. fi\n");
  161.  
  162.     if (version != 0)  {
  163.         fprintf(stderr, "\nCreating version %s shar file.\n\n", version);
  164.         fprintf(outfile, "echo shar file version: %s\n", version);
  165.         }
  166.         
  167.     if (keeptimes) {
  168.         fprintf(stderr, "\nTime stamps will be preserved in both shar and unshar\n\n");
  169.         fflush(stderr);
  170.         }
  171.         
  172.     fprintf(stderr, "%s:\n",
  173.         existed && Append ? "Appending" : "Installing");
  174.     fflush(stderr);
  175.     ++Level;
  176.     
  177.     AddChksum();
  178.     if (keeptimes) AddTimeKeeper();
  179.     
  180.     for (c = optind; c < argc; c++) {
  181.         if (rflag) {
  182.             register char *n = tail(argv[c]);
  183.             if (n)
  184.                 Add(n, 0, NULL);
  185.         } else
  186.             Add(argv[c], 0, NULL);
  187.     }
  188.     
  189.     /* remove the checksum generator and the utime setter */
  190.     fprintf(outfile, "rm /tmp/chksum$$.c\n");
  191.     fprintf(outfile, "rm /tmp/chksum$$\n");
  192.     
  193.     if (keeptimes) {
  194.         fprintf(outfile, "rm /tmp/setutimes$$.c\n");
  195.         fprintf(outfile, "rm /tmp/setutimes$$\n");
  196.         }
  197.     if (Errors)
  198.         fprintf(stderr, "\nDone, but I had trouble with %d file%s\n",
  199.             Errors, Errors == 1 ? "" : "s");
  200.     else
  201.         fprintf(stderr, "\nDone.\n");
  202.     exit(Errors > 127 ? 127 : Errors);
  203. }
  204.  
  205. /*
  206.  * Return the trailing component of a pathname, sneakily changing directories
  207.  * if necessary.
  208.  */
  209. char *
  210. tail(n)
  211.     register char *n;
  212. {
  213.     register char *p = n, *dir = n;
  214.     static elsewhere;    /* true => not in WDir */
  215.  
  216.     while (*p == '/')
  217.         p++;        /* skip any leading '/'s */
  218.  
  219.     if (*n == '/') {    /* seems to be absolute; set n to last '/' */
  220.         while (*p)
  221.             if (*p++ == '/' && *p != '/' && *p)
  222.                 n = p;
  223.         if (n != dir) {    /* n is tail of name, dir is directory */
  224. do_chdir:            /* chdir to dir, return n */
  225.             n[-1] = 0;
  226.             if (chdir(dir)) {
  227.                 error(0, errno,
  228.                       "can't change to directory \"%s\"", dir);
  229.                 Errors++;
  230.                 return (0);
  231.             }
  232.             elsewhere++;
  233.             return (n);
  234.         }
  235.     }
  236.     /* must be relative to original working directory, so go there */
  237.     if (elsewhere) {
  238.         if (chdir(WDir)) {
  239.             error(0, errno, "can't change to directory \"%s\"",
  240.                   WDir);
  241.             Errors++;
  242.             return (0);
  243.         }
  244.         elsewhere = 0;
  245.     }
  246.     while (*p)
  247.         if (*p++ == '/' && *p != '/' && *p)
  248.             n = p;    /* Find last slash */
  249.     if (n != dir)
  250.         goto do_chdir;
  251.     return (n);
  252. }
  253.  
  254. /* Set up the ID numbers for Root, Bin, and Daemon */
  255. GetIDs()
  256. {
  257.     register struct passwd *p;
  258.     struct passwd *getpwnam();
  259.  
  260.     /* RootID = 0; */        /* Already set */
  261.     if (p = getpwnam("bin"))
  262.         BinID = p->pw_uid;
  263.     if (p = getpwnam("daemon"))
  264.         DaemonID = p->pw_uid;
  265.     endpwent();
  266. }
  267.  
  268. /*
  269.  * Add the named file into the script, performing the right actions depending
  270.  * on the type of the file, and changing the owner/mode as appropriate.
  271.  */
  272. Add(fn, cc, cc_out)
  273.     register char *fn;
  274.     register int cc;
  275.     register char *cc_out;
  276. {
  277.     struct exec test_exec;
  278.     struct stat st;
  279.     char *u;
  280.     register int level = Level;
  281.  
  282.     if (stat(fn, &st)) {
  283.         error(0, errno, "can't access \"%s\"", fn);
  284.         Errors++;
  285.         return;
  286.     }
  287.     while (--level > 0)
  288.         putc('\t', stderr);
  289.     fprintf(stderr, "%s", fn);
  290.     if (keeptimes) fprintf(stderr, "  (time stamps preserved)");
  291.     fflush(stderr);
  292.     switch (st.st_mode & S_IFMT) {
  293.  
  294.     case S_IFREG:
  295.         if (st.st_size >= sizeof test_exec) {
  296.             FILE *fp = fopen(fn, "r");
  297.             if (fp == 0) {
  298.                 fprintf(stderr, ": can't open\n");
  299.                 fflush(stderr);
  300.                 Errors++;
  301.                 return;
  302.             }
  303.             if (fread(&test_exec, sizeof test_exec, 1, fp) == 1
  304.                 && !N_BADMAG(test_exec)) {
  305.                 fclose(fp);
  306.                 if (AddExec(fn, " (executable)"))
  307.                     return;
  308.                 break;
  309.             }
  310.             fclose(fp);
  311.         }
  312.         if (IsDataFile(fn) ? AddExec(fn, " (data)") : AddFile(fn))
  313.             return;
  314.         break;
  315.  
  316.     case S_IFDIR:
  317.         if (AddDir(fn))
  318.             return;
  319.         break;
  320.  
  321.     case S_IFCHR:
  322.         AddNode(fn, "character", st.st_dev);
  323.         break;
  324.  
  325.     case S_IFBLK:
  326.         AddNode(fn, "block", st.st_dev);
  327.         break;
  328.  
  329. #ifdef    S_IFMPC            /* not in 4.2 */
  330.     case S_IFMPC:
  331.     case S_IFMPB:
  332.         fprintf(stderr, " Multiplexed!\n");
  333.         fflush(stderr);
  334.         Errors++;
  335.         return;
  336. #endif    S_IFMPC
  337.  
  338. #ifdef    S_IFSOCK
  339.     case S_IFSOCK:
  340.         fprintf(stderr, " Socket!\n");
  341.         fflush(stderr);
  342.         Errors++;
  343.         return;
  344. #endif    S_IFSOCK
  345.  
  346.     }
  347.     if (st.st_uid == RootID) {
  348.         u = "root";
  349.         goto changeown;
  350.     }
  351.     if (st.st_uid == BinID) {
  352.         u = "bin";
  353.         goto changeown;
  354.     }
  355.     if (st.st_uid == DaemonID) {
  356.         u = "daemon";
  357. changeown:
  358.         fprintf(outfile, "\
  359. if [ $all = TRUE ]; then\n\
  360. \techo '\tChanging owner to %s'\n\
  361. \tchown %s %s\n\
  362. else\n\
  363. \techo '\tOriginal owner was %s'\n\
  364. fi\n",
  365.             u, u, fn, u);
  366.     }
  367.     fn = protect(fn);
  368.     
  369.     
  370.     fprintf(outfile, "\
  371. if [ $made = TRUE ]; then\n\
  372. \tchmod %o %s\n", st.st_mode & 07777, fn);
  373.  
  374.     /* do we need to compile this file? */
  375.     if (cc) fprintf(outfile, "\
  376. \tcc -o %s %s\n", cc_out, fn);
  377.  
  378.     /* do we need to preserve time stamps? */
  379.     if (keeptimes) fprintf(outfile, "\
  380. \t/tmp/setutimes$$ %ld %ld %s\n", st.st_atime, st.st_mtime, fn);
  381.     
  382.     fprintf(outfile, "\
  383. \techo -n '\t'; ls -ld %s\n\
  384. fi\n", fn);
  385.             
  386.     if ((st.st_mode & S_IFMT) != S_IFDIR) {
  387.         putc('\n', stderr);
  388.         fflush(stderr);
  389.     }
  390. }
  391.  
  392. /* Add a character or block device */
  393. AddNode(fn, type, dev)
  394.     register char *fn, *type;
  395.     dev_t dev;
  396. {
  397.     register int ma = major(dev), mi = minor(dev);
  398.  
  399.     fn = protect(fn);
  400.     fprintf(stderr, " (%s special)", type);
  401.     fflush(stderr);
  402.     fprintf(outfile, "\
  403. if [ $all = TRUE ]; then\n\
  404. \techo Making %s special device %s number '(%d, %d)'\n\
  405. \tmknod %s %c %d %d\n\
  406. made=TRUE\n\
  407. else\n\
  408. \techo Not making %s special device %s number '(%d, %d)'\n\
  409. made=FALSE\n\
  410. fi\n",
  411.         type, fn, ma, mi, fn, *type, ma, mi, type, fn, ma, mi);
  412. }
  413.  
  414. AddFile(fn)
  415.     register char *fn;
  416. {
  417.     register int c, wantx = 1;
  418.     register FILE *fp = fopen(fn, "r");
  419.     register int wc;
  420.     int chk;
  421.  
  422.     if (fp == NULL) {
  423.         fprintf(stderr, ": can't open\n");
  424.         fflush(stderr);
  425.         Errors++;
  426.         return (-1);
  427.     }
  428.     fn = protect(fn);
  429.     chk = getchksum(fn);
  430.     fprintf(outfile, "\
  431. echo Extracting %s\n\
  432. sed 's/^X//' <<'//go.sysin dd *' >%s\n",
  433.         fn, fn);
  434.     wc = 0;
  435.     while ((c = getc(fp)) != EOF) {
  436.         if (wantx) {
  437.             if (c == 'X' || c == '.' || c == '/' || c == 'F')
  438.                 putc('X', outfile);
  439.             wantx = 0;
  440.         }
  441.         putc(c, outfile);
  442.         if (c == '\n')
  443.             wantx++;
  444.         wc++;
  445.     }
  446.     fclose(fp);
  447.     if (!wantx) {        /* oops, have to add a newline */
  448.         fprintf(stderr, " [incomplete last line]");
  449.         fflush(stderr);
  450.         putc('\n', outfile);
  451.         wc++;
  452.     }
  453.     fprintf(outfile, "//go.sysin dd *\n");
  454.     fprintf(outfile, "if [ `wc -c < %s` != %d ]; then\n\
  455. \tmade=FALSE\n\
  456. \techo error transmitting %s --\n\
  457. \techo length should be %d, not `wc -c < %s`\n\
  458. else\n\
  459. \tmade=TRUE\n\
  460. fi\n",
  461.         fn, wc, fn, wc, fn);
  462.     fprintf(outfile, "if [ `/tmp/chksum$$ %s` != %d ]; then\n\
  463. \tmade=FALSE\n\
  464. \techo checksum is incorrect for %s --\n\
  465. \techo checksum should be %d, not `/tmp/chksum$$ %s`\n\
  466. else\n\
  467. \tmade=TRUE\n\
  468. fi\n", fn, chk, fn, chk, fn);
  469.     return (0);
  470. }
  471.  
  472. /* Return true iff the file 'fn' is a data file */
  473. IsDataFile(fn)
  474.     char *fn;
  475. {
  476.     register int n, l;
  477.     int pipes[2];
  478.     char buf[201];
  479.  
  480.     if (AssumeNoDataFiles)
  481.         return (0);
  482.     if (pipe(pipes))
  483.         return (-1);    /* call it data anyway */
  484.     fflush(stderr);
  485.     if (vfork() == 0) {
  486.         close(0);
  487.         dup2(pipes[1], 1);
  488.         close(pipes[0]);
  489.         close(pipes[1]);
  490.         execl("/usr/bin/file", "file", fn, 0);
  491.         fprintf(stderr, " can't exec /usr/bin/file");
  492.         fflush(stderr);
  493.         _exit(0);
  494.     }
  495.     close(pipes[1]);
  496.     l = 0;
  497.     while ((n = sizeof buf - l - 1) > 0) {
  498.         if ((n = read(pipes[0], buf + l, n)) <= 0)
  499.             break;
  500.         l += n;
  501.     }
  502.     close(pipes[0]);
  503.     buf[l] = 0;
  504.     while (wait((int *)0) != -1)
  505.         ;
  506.     if (strlen(buf) <= (l = strlen(fn)))
  507.         return (1);
  508.     if (contains(buf + l, "text"))
  509.         return (0);
  510.     if (contains(buf + l, "script"))
  511.         return (0);
  512.     if (contains(buf + l, "commands"))
  513.         return (0);
  514.     return (1);
  515. }
  516.  
  517. /* Write stuff to extract an executable */
  518. AddExec(fn, type)
  519.     register char *fn;
  520.     char *type;
  521. {
  522.     char *pfn = protect(fn);
  523.  
  524.     fprintf(stderr, type);
  525.     fflush(stderr);
  526.     fprintf(outfile,
  527.         "echo Decoding %s\nuudecode << '//go.sysin dd *'\n",
  528.         pfn);
  529.     fflush(outfile);
  530.     if (vfork() == 0) {
  531.         (void) dup2(fileno(outfile), 1);
  532.         execl("/usr/bin/uuencode", "uuencode", fn, fn, 0);
  533.         fprintf(stderr, "Help! Can't exec /usr/bin/uuencode\n");
  534.         exit(0);
  535.     }
  536.     while (wait((int *)0) != -1)
  537.         ;
  538.     fprintf(outfile, "//go.sysin dd *\nmade=TRUE\n");
  539.     return (0);
  540. }
  541.  
  542. /* Compare function for qsort */
  543. DirCmp(d1, d2)
  544.     register struct direct *d1, *d2;
  545. {
  546.  
  547. #ifndef    LIBNDIR
  548.     return (strncmp(d1->d_name, d2->d_name, DIRSIZ));
  549. #else    LIBNDIR
  550.     return (strncmp(d1->d_name, d2->d_name,
  551.             max(d1->d_namlen, d2->d_namlen)));
  552. #endif    LIBNDIR
  553. }
  554.  
  555. /* Add a directory: recursion time */
  556. #ifndef    LIBNDIR
  557. AddDir(fn)
  558.     char *fn;
  559. {
  560.     int f;
  561.     struct stat st;
  562.     char nmbuf[BUFSIZ];
  563.     register char *cp;
  564.     struct direct *d;
  565.     register struct direct *p, *dp, *pp;
  566.     char *pfn = protect(fn);
  567.  
  568.     fprintf(outfile,
  569.         "echo Making directory %s\nmkdir %s\n", pfn, pfn);
  570.     if ((f = open(fn, 0)) < 0) {
  571.         fprintf(stderr, ": can't open\n");
  572.         fflush(stderr);
  573.         Errors++;
  574.         return (-1);
  575.     }
  576.     fprintf(stderr, ": directory");
  577.     fflush(stderr);
  578.     fstat(f, &st);
  579.     if (st.st_size == 0) {
  580.         fprintf(stderr, " (empty!)");
  581.         fflush(stderr);
  582.         close(f);
  583.         return (0);
  584.     }
  585.     d = (struct direct *) malloc(st.st_size);
  586.     pp = dp = (struct direct *) malloc(st.st_size);
  587.     if (read(f, (char *) d, st.st_size) != st.st_size) {
  588.         fprintf(stderr, ": read error\n");
  589.         fflush(stderr);
  590.         close(f);
  591.         Errors++;
  592.         return (-1);
  593.     }
  594.     close(f);
  595.     putc('\n', stderr);
  596.     fflush(stderr);
  597.     Level++;
  598.     for (p = d; p < &d[st.st_size / sizeof *d]; p++) {
  599.         if (p->d_name[0] == '.') {
  600.             if (p->d_name[1] == 0)
  601.                 continue;
  602.             if (p->d_name[1] == '.' && p->d_name[2] == 0)
  603.                 continue;
  604.         }
  605.         if (p->d_ino)
  606.             *pp++ = *p;
  607.     }
  608.     free(d);
  609.     qsort(dp, pp - dp, sizeof *dp, DirCmp);
  610.     for (cp = nmbuf; *cp++ = *fn++;)
  611.         ;
  612.     cp[-1] = '/';
  613.     for (p = dp; p < pp; p++) {
  614.         strncpy(cp, p->d_name, DIRSIZ);
  615.         cp[DIRSIZ] = 0;
  616.         Add(nmbuf, 0, NULL);
  617.     }
  618.     Level--;
  619.     free(dp);
  620.     fprintf(outfile, "made=TRUE\n");
  621.     return (0);
  622. }
  623.  
  624. #else    LIBNDIR
  625.  
  626. AddDir(fn)
  627.     char *fn;
  628. {
  629.     int f, g;
  630.     char nmbuf[BUFSIZ];
  631.     char *cp, *pfn;
  632.     struct direct *d, *dp, *p;
  633.     DIR *dd;
  634.  
  635.     pfn = protect(fn);
  636.     fprintf(outfile,
  637.         "echo Making directory %s\nmkdir %s\n", pfn, pfn);
  638.     if ((dd = opendir(fn)) == NULL) {
  639.         fprintf(stderr, ": can't open\n");
  640.         fflush(stderr);
  641.         Errors++;
  642.         return (-1);
  643.     }
  644.     fprintf(stderr, ": directory");
  645.     fflush(stderr);
  646.     for (f = 0; p = readdir(dd); f++)
  647.         continue;
  648.     if (f == 0) {
  649. empty:
  650.         fprintf(stderr, " (empty)");
  651.         fflush(stderr);
  652.         closedir(dd);
  653.         return (0);
  654.     }
  655. again:
  656.     f += 10;
  657.     d = (struct direct *) malloc((unsigned) (f * sizeof(struct direct)));
  658.     rewinddir(dd);
  659.     for (dp = d, g = 0; p = readdir(dd);) {
  660.         if ((p->d_namlen == 1 && !strcmp(p->d_name, "."))
  661.             || (p->d_namlen == 2 && !strcmp(p->d_name, "..")))
  662.             continue;
  663.         if (f <= g++) {    /* directory grew!!! */
  664.             for (f = g; p = readdir(dd); f++)
  665.                 continue;
  666.             goto again;
  667.         }
  668.         dp->d_ino = p->d_ino;
  669.         dp->d_reclen = sizeof(struct direct);
  670.         dp->d_namlen = p->d_namlen;
  671.         strcpy(dp->d_name, p->d_name);
  672.         dp++;
  673.     }
  674.     if (d == dp) {
  675.         free(d);
  676.         goto empty;
  677.     }
  678.     closedir(dd);
  679.  
  680.     putc('\n', stderr);
  681.     fflush(stderr);
  682.     Level++;
  683.     qsort(d, dp - d, sizeof *dp, DirCmp);
  684.     for (cp = nmbuf; *cp++ = *fn++;)
  685.         ;
  686.     cp[-1] = '/';
  687.     for (p = d; p < dp; p++) {
  688.         strcpy(cp, p->d_name);
  689.         Add(nmbuf, 0, NULL);
  690.     }
  691.     Level--;
  692.  
  693.     free(d);
  694.     fprintf(outfile, "made=TRUE\n");
  695.     return (0);
  696. }
  697. #endif    LIBNDIR
  698.  
  699. /* Return true if "little" is contained within "big" */
  700. contains(big, little)
  701.     register char *big, *little;
  702. {
  703.     register char *bp, *lp;
  704.  
  705.     while (*big) {
  706.         if (*big++ != *little)
  707.             continue;
  708.         bp = big, lp = little + 1;
  709.         while (*lp)
  710.             if (*bp++ != *lp++)
  711.                 goto cont;
  712.         return (1);
  713. cont:        ;
  714.     }
  715.     return (0);
  716. }
  717.  
  718. /*
  719.  * Protect against meta-characters in file names.
  720.  */
  721. char *
  722. protect(fn)
  723.     register char *fn;
  724. {
  725.     static char pfn[BUFSIZ];
  726.     register char *p = pfn;
  727.  
  728.     while (*p = *fn++) {
  729.         switch (*p++) {
  730.  
  731.         case '*': case '[': case ']': case '?':
  732.         case ';': case '|': case '`': case '\\':
  733.         case '$': case '^': case '&': case '<':
  734.         case '>': case '#': case '(': case ')':
  735.         case ' ': case '\t':
  736.             p[-1] = '\\';
  737.             *p++ = fn[-1];
  738.         }
  739.     }
  740.     *p = 0;
  741.     return (pfn);
  742. }
  743.  
  744. /* Alan Ishigo */
  745.  
  746. int getchksum(fn)
  747. char *fn;
  748. {
  749.     FILE *f;
  750.     int acc;
  751.     char c;
  752.     
  753.     acc = 0;
  754.     f = fopen(fn, "r");
  755.     if (f == NULL) {
  756.         fprintf(stderr, "Unable to read %s for checksum calculation!\n", fn);
  757.         return(0);
  758.         }
  759.     while ((c = getc(f)) != EOF) {
  760.         acc = acc + c;
  761.         acc = acc << 1;
  762.         while (acc < 0) acc = shift(acc);
  763.         }
  764.     fclose(f);
  765.     return(acc);
  766. }    /* getchksum */
  767.  
  768. int shift(n)
  769. int n;
  770. {
  771.     int val;
  772.      
  773.     val = n << 1;
  774.     if (n < 0) val = val | 01;
  775.     return(val);
  776. }    /* shift */
  777.  
  778.  
  779.  
  780. /*
  781.  * error - University of Maryland specific (sigh)
  782.  *
  783.  * Useful for printing error messages.  Will print the program name
  784.  * and (optionally) the system error associated with the values in
  785.  * <errno.h>.
  786.  *
  787.  * Note that the type (and even the existence!) of ``arg'' is undefined.
  788.  */
  789. error(quit, e, fmt, arg)
  790.     int quit;
  791.     register int e;
  792.     char *fmt;
  793. {
  794.     extern char *sys_errlist[];
  795.     extern int sys_nerr;
  796.     register char *p = _argv0;
  797.  
  798.     if (p != NULL) {
  799. #ifdef optional
  800.         char *s, *rindex();
  801.  
  802.         if ((s = rindex(p, '/')) != NULL)
  803.             p = s + 1;
  804. #endif
  805.         (void) fprintf(stderr, "%s: ", p);
  806.     }
  807.     _doprnt(fmt, &arg, stderr);    /* magic */
  808.     if (e > 0) {
  809.         if (e < sys_nerr)
  810.             (void) fprintf(stderr, ": %s", sys_errlist[e]);
  811.         else
  812.             (void) fprintf(stderr, ": unknown error number %d", e);
  813.     }
  814.     (void) putc('\n', stderr);
  815.     (void) fflush(stderr);
  816.     if (quit)
  817.         exit(quit);
  818.  
  819. AddTimeKeeper()
  820. {
  821.     fprintf(outfile, "\
  822. echo Time stamps have been preserved\n\n\
  823. echo Extracting /tmp/setutimes$$.c\n\
  824. sed 's/^X//' <<'//go.sysin dd *' >/tmp/setutimes$$.c\n\n\
  825. #include <stdio.h>\n\
  826. #include <sys/types.h>\n\
  827. #include <sys/time.h>\n\n\n\
  828. main(argc, argv)\n\
  829. int argc;\n\
  830. char *argv[];\n\
  831. {\n\
  832. \ttime_t times[2];\n\
  833. \tint n;\n\n\
  834. \tif (argc < 3) {\n\
  835. \t\tfprintf(stderr, \"Invalid number of arguments.\\n\");\n\
  836. \t\texit(-1);\n\
  837. \t\t}\n\n\
  838. \tn = sscanf(argv[1], \"%%ld\", ×[0]);\n\
  839. \tn = sscanf(argv[2], \"%%ld\", ×[1]);\n\n\
  840. \tif (utime(argv[3], times) < 0) {\n\
  841. \t\tfprintf(stderr, \"Unable to set times.\\n\");\n\
  842. \t\texit(-2);\n\
  843. \t\t}\n\n\
  844. }    /* main */\n\n\n\n\
  845. //go.sysin dd *\n\
  846. if [ `wc -c < /tmp/setutimes$$.c` != 417 ]; then\n\
  847. \tmade=FALSE\n\
  848. \techo error transmitting /tmp/setutimes$$.c --\n\
  849. \techo length should be 417, not `wc -c < /tmp/setutimes$$.c`\n\
  850. else\n\
  851. \tmade=TRUE\n\
  852. fi\n\
  853. if [ $made = TRUE ]; then\n\
  854. \tchmod 664 /tmp/setutimes$$.c\n\
  855. \techo Compiling /tmp/setutimes$$\n\
  856. \tcc -O -o /tmp/setutimes$$ /tmp/setutimes$$.c\n\
  857. \techo -n '    '; ls -ld /tmp/setutimes$$.c\n\
  858. \techo -n '    '; ls -ld /tmp/setutimes$$\n\
  859. fi\n");
  860. }
  861.  
  862. AddChksum()
  863. {
  864.     fprintf(outfile, "\
  865. echo Checksum program\n\
  866. echo Extracting /tmp/chksum$$.c\n\
  867. sed 's/^X//' <<'//go.sysin dd *' >/tmp/chksum$$.c\n\n\
  868. #include <stdio.h>\n\
  869. main(argc, argv)\n\
  870. int argc;\n\
  871. char *argv[];\n\
  872. {\n\
  873. \tFILE *f;\n\
  874. \tint acc;\n\
  875. \tchar c;\n\n\
  876. \tacc = 0;\n\
  877. \tf = fopen(argv[1], \"r\");\n\
  878. \tif (f == NULL) {\n\
  879. \t\tfprintf(stdout, \"%%d\\n\", 0);\n\
  880. \t\texit(-1);\n\
  881. \t\t}\n\
  882. \twhile ((c = getc(f)) != EOF) {\n\
  883. \t\tacc = acc + c;\n\
  884. \t\tacc = acc << 1;\n\
  885. \t\twhile (acc < 0) acc = shift(acc);\n\
  886. \t\t}\n\
  887. \tfclose(f);\n\
  888. \tfprintf(stdout, \"%%d\\n\", acc);\n\
  889. \texit(acc);\n\
  890. }\n\n\
  891. int shift(n)\n\
  892. int n;\n\
  893. {\n\
  894. \tint val;\n\n\
  895. \tval = n << 1;\n\
  896. \tif (n < 0) val = val | 01;\n\
  897. \treturn(val);\n\
  898. }\n\n\
  899. //go.sysin dd *\n\
  900. if [ `wc -c < /tmp/chksum$$.c` != 451 ]; then\n\
  901. \tmade=FALSE\n\
  902. \techo error transmitting /tmp/chksum$$.c --\n\
  903. \techo length should be 451, not `wc -c < /tmp/chksum$$.c`\n\
  904. else\n\
  905. \tmade=TRUE\n\
  906. fi\n\
  907. if [ $made = TRUE ]; then\n\
  908. \tchmod 664 /tmp/chksum$$.c\n\
  909. \techo Compiling /tmp/chksum$$\n\
  910. \tcc -O -o /tmp/chksum$$ /tmp/chksum$$.c\n\
  911. \techo -n '    '; ls -ld /tmp/chksum$$.c\n\
  912. \techo -n '    '; ls -ld /tmp/chksum$$\n\
  913. fi\n");
  914. }
  915.  
  916.  
  917.